package jt

import (
	"github.com/dontls/xproto"
)

func dtu(dtu []byte) string {
	tm := bcd2Number(dtu)
	tm = "20" + tm[:2] + "-" + tm[2:4] + "-" + tm[4:6] + " " + tm[6:8] + ":" + tm[8:10] + ":" + tm[10:]
	return tm
}

func jtgps(val uint32) float32 {
	return float32(val) / 1000000
}

type Status struct {
	Speed          uint16   `json:"speed"`    // attachID 0x03 1/10km/h
	ManualID       uint16   `json:"manualID"` // attachID 0x04
	OverSpeedAlarm struct { // attachID 0x11 表28
		LocalType uint8  `json:"localType"` //
		AreaID    uint32 `json:"areaID"`
	} `json:"overSpeedAlarm"`
	AreaAlarm struct { // attachID 0x12 表29
		Type      uint8  `json:"type"` //
		ID        uint32 `json:"id"`
		Direction uint8  `json:"direction"`
	} `json:"areaAlarm"`
	LineAlarm struct { // attachID 0x13 表30
		ID       uint32 `json:"id"`
		Duration uint16 `json:"duration"` //
		Result   uint8  `json:"result"`
	} `json:"lineAlarm"`
	Signalsate uint32 `json:"signalsate"` // attachID 0x25 表31
	Iosate     uint16 `json:"iosate"`     // attachID 0x2A 表32
	Analog     uint32 `json:"analog"`     //attachID 0x2B  模拟量，bit0-15，AD0；bit16-31，AD1。
	// FollowLength
}

func (b *jtBytes) toJtAStatus(s *xproto.Status) (r Status) {
	for b.pos < len(b.Bytes) {
		attachID := b.toByte()
		length := int(b.toByte())
		switch attachID {
		case 0x01:
			s.Mileage.Now = b.toDWord() * 10
		case 0x02:
			s.Oils = append(s.Oils, float32(b.toWord()*10))
		case 0x03:
			b.toWord() // 行驶记录功能获取的速度，WORD，1/10km/h
		case 0x04:
			b.toWord() // 需要人工确认报警事件的 ID，WORD，从 1 开始计数
		case 0x11: // 1 或 5 超速报警附加信息见 表 28
			r.OverSpeedAlarm.LocalType = b.toByte()
			if r.OverSpeedAlarm.LocalType > 0 {
				r.OverSpeedAlarm.AreaID = b.toDWord()
			}
		case 0x12:
			r.AreaAlarm.Type = b.toByte()
			r.AreaAlarm.ID = b.toDWord()
			r.AreaAlarm.Direction = b.toByte()
		case 0x13:
			r.LineAlarm.ID = b.toDWord()
			r.LineAlarm.Duration = b.toWord()
			r.LineAlarm.Result = b.toByte()
		case 0x25:
			r.Signalsate = b.toDWord() // bit位
		case 0x2A:
			r.Iosate = b.toWord()
		case 0x2B:
			r.Analog = b.toDWord()
		case 0x30:
			s.Mobile.Signal = b.toByte()
		case 0x31:
			s.Location.Satellites = b.toByte()
		case 0x64: // adas
			b.toAdvanceAssistance()
		case 0x65: // dsm
		case 0x66: // tpms
		case 0x67: // bsd
		default:
			b.toArray(length)
		}
		// log.Printf("attachID %d\n", attachID)
	}
	return
}

// satus 表
// 位 状态
// 0 0：ACC 关；1： ACC 开
// 1 0：未定位；1：定位
// 2 0：北纬；1：南纬
// 3 0：东经；1：西经
// 4 0：运营状态；1：停运状态
// 5 0：经纬度未经保密插件加密；1：经纬度已经保密插件加密
// 6-7 保留
// 8-9 00：空车；01：半载；10：保留；11：满载 （可用于客车的空、重车及货车的空载、满载状态表示，人工输入或传感器获取）
// 10 0：车辆油路正常；1：车辆油路断开
// 11 0：车辆电路正常；1：车辆电路断开
// 12 0：车门解锁；1：车门加锁
// 13 0：门 1 关；1：门 1 开（前门）
// 14 0：门 2 关；1：门 2 开（中门）
// 15 0：门 3 关；1：门 3 开（后门）
// 16 0：门 4 关；1：门 4 开（驾驶席门）
// 17 0：门 5 关；1：门 5 开（自定义）
// 18 0：未使用 GPS 卫星进行定位；1：使用 GPS 卫星进行定位
// 19 0：未使用北斗卫星进行定位；1：使用北斗卫星进行定位
// 20 0：未使用 GLONASS 卫星进行定位；1：使用 GLONASS 卫星进行定位
// 21 0：未使用 Galileo 卫星进行定位；1：使用 Galileo 卫星进行定位
// 22-31 保留

// doStatusParse 解析位置信息 28byte
func (o *Client) doStatusParse(b *jtBytes) (s xproto.Status, alrflag uint32) {
	s.DeviceNo = o.DeviceNo
	alrflag = b.toDWord()
	satus := b.toDWord()
	s.Acc = uint8(satus & 0x01)
	s.Location.Type = uint8(satus & 0x02)
	s.Location.Latitude = jtgps(b.toDWord())
	if (satus & 0x04) > 0 {
		s.Location.Latitude *= -1
	}
	s.Location.Longitude = jtgps(b.toDWord())
	if (satus & 0x08) > 0 {
		s.Location.Longitude *= -1
	}
	s.Location.Altitude = int(b.toWord())
	s.Location.Speed = float32(b.toWord()) / 100.0
	s.Location.Angle = float32(b.toWord())
	s.DTU = dtu(b.toArray(6))
	s.Payload = b.toJtAStatus(&s)
	return
}

func (o *Client) doCacheAlarmTs(alr *xproto.Alarm, i int, dtu string) {
	alr.DTU = dtu
	// 判断上次报警状态
	if (o.lstAlarm>>i)&0x01 == 0 {
		o.cAlarmTs[i] = dtu
		alr.StartTime = dtu
		return
	}
	// 报警结束
	if st := o.cAlarmTs[i]; st == "" {
		alr.StartTime = dtu
	} else {
		alr.StartTime = st
		o.cAlarmTs[i] = ""
	}
	alr.EndTime = dtu
}

func setbit(s *uint32, i int) {
	mask := 1 << i
	*s = *s | uint32(mask)
}

func (o *Client) onRecvAlarm(alrflag uint32, st *xproto.Status, b *jtBytes, handler func(*xproto.Alarm)) {
	flag := alrflag ^ o.lstAlarm
	if flag == 0 {
		return
	}
	for i := 0; i < 32; i++ {
		if (flag>>i)&0x01 == 0 {
			continue
		}
		var alr xproto.Alarm
		alr.Status = st
		switch i {
		case 0:
			setbit(&o.lstAlarm, i)
			alr.Type = xproto.AlrUrgency //ack
			o.WriteAck(0)
		case 1:
			alr.Type = xproto.AlrOverSpeed
		case 2:
			alr.Type = xproto.AlrFatigueDriving
		case 4:
			alr.Type = xproto.AlrLocationModuleException // 定位模块异常
		case 5:
			alr.Type = xproto.AlrGpsAntennaOpen // Gps天线断开
		case 6:
			alr.Type = xproto.AlrGpsAntennaCircuit // Gps天线短路
		case 7:
			alr.Type = xproto.AlrVoltageWarn // 低压
			alr.Data = xproto.AlarmVoltage{Dt: "1"}
		case 8:
			alr.Type = xproto.AlrVoltageWarn // 掉电
			alr.Data = xproto.AlarmVoltage{Dt: "3"}
		case 11:
			alr.Type = xproto.AlrVideoAnomaly // 视频异常
		case 13:
			alr.Type = xproto.AlrOverSpeedWarn
		// case 14: // 疲劳驾驶预警
		// 	alr.Type = "17"
		case 19:
			alr.Type = xproto.AlrParkTimeout
			alr.Data = xproto.AlarmPark{}
		case 27:
			setbit(&o.lstAlarm, i)           // 设置为结束报警
			alr.Type = xproto.AlrIllegalFire // ack
			o.WriteAck(0)
		case 29:
			alr.Type = xproto.AlrShake
			alr.Data = xproto.AlarmShake{Dt: "4"}
		case 30:
			alr.Type = xproto.AlrShake
			alr.Data = xproto.AlarmShake{Dt: "5"}
		default:
			continue
		}
		o.doCacheAlarmTs(&alr, i, st.DTU)
		handler(&alr)
	}
	o.lstAlarm = alrflag
}
